#include "handler/basic_command.h"
#include "ds/path_stack.h"
#include "db/file.h"
#include "logger.h"
#include "color.h"

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <math.h>

// 在字符串前面拼接指定字符串的函数
static void prependString(char *original, const char *toPrepend)
{
    if (toPrepend == NULL)
    {
        return;
    }
    size_t original_len = strlen(original);
    size_t toPrepend_len = strlen(toPrepend);

    // 将原始字符串右移，腾出空间来插入要拼接的字符串
    memmove(original + toPrepend_len, original, original_len + 1);

    // 将要拼接的字符串复制到原始字符串的开头
    memcpy(original, toPrepend, toPrepend_len);
}

static void formatFileSize(char *buffer, size_t size, size_t file_size)
{
    if (file_size < 1024)
    {
        sprintf(buffer, "%6zu B", file_size);
    }
    else if (file_size < 1024 * 1024)
    {
        sprintf(buffer, "%6.2f K", file_size / 1024.0);
    }
    else if (file_size < 1024 * 1024 * 1024)
    {
        sprintf(buffer, "%6.2f M", file_size / (1024.0 * 1024.0));
    }
    else
    {
        sprintf(buffer, "%6.2f G", file_size / (1024.0 * 1024.0 * 1024.0));
    }
}

int lsCmd(Response_t *resp, Client_t *cli, MYSQL *conn)
{
    char cur_path[256] = {0};
    strcpy(cur_path, cli->cur_path);

    char sql_select[512] = {0};
    size_t capacity = 1024; // 初始容量，按需扩展
    resp->resp = (char *)calloc(1, capacity);
    if (resp->resp == NULL)
    {
        PRINT_ERROR("calloc resp");
        resp->if_success = false;
        return -1;
    }

    MYSQL_RES *result = NULL;
    MYSQL_ROW row;
    // 获取用户id
    sprintf(sql_select, "select user_id from users where username = '%s'", cli->user_info.name);
    // LOG_DEBUG("Basic Cmd", "获取用户id = %s", sql_select);

    result = excutesql(sql_select, conn);

    row = mysql_fetch_row(result);
    int user_id = atoi(row[0]);
    mysql_free_result(result);

    // 获取父目录id
    memset(sql_select, 0, sizeof(sql_select));
    sprintf(sql_select, "select file_id from files where file_path = '%s' and user_id = %d", cur_path, user_id);
    // LOG_DEBUG("Basic Cmd", "获取父目录id = %s", sql_select);

    result = excutesql(sql_select, conn);

    row = mysql_fetch_row(result);
    int parent_id = atoi(row[0]);
    mysql_free_result(result);

    // 查询当前目录的所有文件
    memset(sql_select, 0, sizeof(sql_select));
    sprintf(sql_select, "select file_name, file_type from files where parent_id = %d and is_del = 0 and user_id = %d", parent_id, user_id);
    LOG_DEBUG("Basic Cmd", "查询当前目录的所有文件 = %s", sql_select);
    result = excutesql(sql_select, conn);

    row = mysql_fetch_row(result);
    if (row == NULL)
    {
        resp->if_success = true;
        return -1;
        // exitError(conn);
    }

    // 后期记得改成用row进行判空处理
    //  判空处理
    while (row != NULL)
    {
        if (strcmp(row[1], "dir") == 0)
        {
            strcat(resp->resp, COLOR_BLUE_BOLD);
            strcat(resp->resp, row[0]);
            strcat(resp->resp, "/\t");
            strcat(resp->resp, COLOR_RESET);
        }
        else if (strcmp(row[1], "file") == 0)
        {
            strcat(resp->resp, COLOR_WHITE);
            strcat(resp->resp, row[0]);
            strcat(resp->resp, "\t");
            strcat(resp->resp, COLOR_RESET);
        }
        row = mysql_fetch_row(result);
    }
    strcat(resp->resp, "\n");
    // puts(resp->resp);
    mysql_free_result(result);
    resp->if_success = true;
    resp->resp_len = strlen(resp->resp); // 重新计算长度

    strcpy(cli->cur_path, cur_path);
    // PRINT_INFO("clipath = %s", cli->cur_path);

    return 0;
}

int llCmd(Response_t *resp, Client_t *cli, MYSQL *conn)
{
    char cur_path[256] = {0};
    strcpy(cur_path, cli->cur_path);

    char sql_select[512] = {0};
    size_t capacity = 1024; // 初始容量，按需扩展
    resp->resp = (char *)calloc(1, capacity);
    if (resp->resp == NULL)
    {
        PRINT_ERROR("calloc resp");
        resp->if_success = false;
        return -1;
    }

    MYSQL_RES *result = NULL;
    MYSQL_ROW row;
    // 获取用户id
    sprintf(sql_select, "select user_id from users where username = '%s'", cli->user_info.name);
    LOG_DEBUG("Basic Cmd", "获取用户id = %s", sql_select);

    result = excutesql(sql_select, conn);

    row = mysql_fetch_row(result);
    int user_id = atoi(row[0]);
    mysql_free_result(result);

    // 获取父目录id
    memset(sql_select, 0, sizeof(sql_select));
    sprintf(sql_select, "select file_id from files where file_path = '%s' and user_id = %d", cur_path, user_id);
    LOG_DEBUG("Basic Cmd", "获取父目录id = %s", sql_select);
    result = excutesql(sql_select, conn);

    row = mysql_fetch_row(result);
    int parent_id = atoi(row[0]);
    mysql_free_result(result);

    // 查询当前目录的所有文件
    memset(sql_select, 0, sizeof(sql_select));
    sprintf(sql_select, "select file_type, file_size, created_time, file_name, created_time from files where parent_id = %d and is_del = 0 and user_id = %d", parent_id, user_id);
    LOG_DEBUG("Basic Cmd", "查询当前目录的所有文件 = %s", sql_select);

    result = excutesql(sql_select, conn);
    row = mysql_fetch_row(result);

    if (row == NULL)
    {
        resp->if_success = true;
        return -1;
        // exitError(conn);
    }

    char size_str[64]; // 用于存储格式化后的文件大小字符串
    while (row != NULL)
    {
        formatFileSize(size_str, sizeof(size_str), atol(row[1]));

        strcat(resp->resp, row[0]); // 文件类型
        strcat(resp->resp, "\t");
        strcat(resp->resp, row[2]); // 创建时间
        strcat(resp->resp, "\t");
        strcat(resp->resp, size_str); // 格式化文件大小
        strcat(resp->resp, "\t");

        if (strcmp(row[0], "dir") == 0)
        {
            strcat(resp->resp, COLOR_BLUE_BOLD);
            strcat(resp->resp, row[3]); // 文件名
            strcat(resp->resp, "/");
            strcat(resp->resp, COLOR_RESET);
        }
        else
        {
            strcat(resp->resp, COLOR_WHITE);
            strcat(resp->resp, row[3]); // 文件名
            strcat(resp->resp, COLOR_RESET);
        }

        strcat(resp->resp, "\n");

        row = mysql_fetch_row(result);
    }

    mysql_free_result(result);
    resp->if_success = true;
    resp->resp_len = strlen(resp->resp); // 重新计算长度

    strcpy(cli->cur_path, cur_path);
    // PRINT_INFO("clipath = %s", cli->cur_path);

    return 0;
}

int cdCmd(Response_t *resp, char *dir_path, Client_t *cli, MYSQL *conn)
{
    char *p_curr_path = NULL;
    char *p_cli_path = NULL;
    char str_cpy[256] = {0};
    if (strlen(dir_path) != 0)
    {
        strcpy(str_cpy, dir_path);
    }
    else
    {
        strcpy(str_cpy, "./");
    }

    p_cli_path = strtok(str_cpy, "/");
    if (p_cli_path == NULL)
    {
        strcpy(cli->cur_path, "/");
        strcpy(resp->pwd, cli->cur_path);
        resp->if_success = true;
        return 0;
    }

    if (!strcmp(p_cli_path, "..")) // 如果输入 cd ..
    {
        Stack *stack = stack_create();
        p_curr_path = strtok(cli->cur_path, "/");
        while (p_curr_path)
        {
            stack_push(stack, p_curr_path);
            p_curr_path = strtok(NULL, "/");
        }
        p_cli_path = strtok(dir_path, "/");
        while (p_cli_path)
        {
            if (!strcmp(p_cli_path, ".."))
            {
                stack_pop(stack);
                p_cli_path = strtok(NULL, "/");
            }
            else
            {
                stack_push(stack, p_cli_path);
                p_cli_path = strtok(NULL, "/");
            }
        }
        char dest[256] = {0};
        while (1)
        {
            prependString(dest, "/");
            if (is_empty(stack))
            {
                break;
            }
            char *tmp = stack_pop(stack);
            prependString(dest, tmp);
        }
        stack_destroy(stack);
        strcpy(cli->cur_path, dest);
        strcpy(resp->pwd, dest);
    }
    else if (!strcmp(p_cli_path, ".")) // 如果输入 cd .
    {
        strcpy(resp->pwd, cli->cur_path);
    }
    else
    {
        // 判断路径是否存在
        MYSQL_RES *result = NULL;
        MYSQL_ROW row;
        char sql_select[512] = {0};
        // 获取用户id
        sprintf(sql_select, "select user_id from users where username = '%s'", cli->user_info.name);
        result = excutesql(sql_select, conn);
        row = mysql_fetch_row(result);
        int user_id = atoi(row[0]);

        // PRINT_DEBUG("dir_path = %s", dir_path);
        char sql[512] = {0};
        sprintf(sql, "select is_del from files where file_path = '%s%s/' and file_type = 1 and user_id = %d", cli->cur_path, dir_path, user_id);
        LOG_DEBUG("Basic Cmd", "查找路径 = %s", sql);

        result = excutesql(sql, conn);
        memset(&row, 0, sizeof(MYSQL_ROW));
        row = mysql_fetch_row(result);
        if (row == NULL)
        {
            char *res = (char *)calloc(128, 1);
            strcpy(res, "path is not exit!");
            resp->resp_len = 128;
            resp->resp = res;
            return -1;
        }

        // 虽然路径存在但已经删除
        int is_del = atoi(row[0]);
        if (is_del)
            return -1;
        strcat(cli->cur_path, dir_path);
        strcat(cli->cur_path, "/");
        strcpy(resp->pwd, cli->cur_path);
    }
    // 做两次strtok是因为存的当前路径开头以“/”开头
    resp->if_success = true;
    return 0;
}

int pwdCmd(Response_t *resp, Client_t *cli)
{
    strcpy(resp->pwd, cli->cur_path);
    resp->if_success = true;
    LOG_DEBUG("Basic Cmd", "pwd = %s", resp->pwd);
    return 0;
}

int removeCmd(Response_t *resp, Command_t *cmd, Client_t *cli, MYSQL *conn)
{
    char sql_select[1024] = {0};
    char sql_update[1024] = {0};
    char dest_path[512] = {0};
    MYSQL_RES *result = NULL;
    MYSQL_ROW row;

    // 获取用户id
    sprintf(sql_select, "select user_id from users where username = '%s'", cli->user_info.name);
    result = excutesql(sql_select, conn);
    row = mysql_fetch_row(result);
    int user_id = atoi(row[0]);
    mysql_free_result(result);

    //获取目标路径
    strcpy(dest_path, cli->cur_path);
    strcat(dest_path, cmd->arg1);

    sprintf(sql_select, "select file_id from files where file_path = '%s' and user_id = %d", dest_path, user_id);

    puts(sql_select);

    result = excutesql(sql_select, conn);
    memset(&row, 0, sizeof(MYSQL_ROW));
    row = mysql_fetch_row(result);
    if (row == NULL)
    {
        char *res = (char *)calloc(128, 1);
        strcpy(res, "dest path is not exit!");
        puts(res);
        resp->resp = res;
        return 0;
    }

    sprintf(sql_update, "update files set is_del = 1 where file_path = '%s' and user_id = %d", dest_path, user_id);
    LOG_DEBUG("Basic Cmd", "删除文件 = %s", sql_select);
    excutesql(sql_update, conn);
    resp->if_success = true;
    return 0;
}

int mkdirCmd(Response_t *resp, char *dir_name, Client_t *cli, MYSQL *conn)
{
    if (strlen(dir_name) == 0)
    {
        resp->if_success = false;

        char *res = CALLOC(char, 50);
        strcpy(res, "failed to mkdir: missing operand");
        PRINT_DEBUG("failed to mkdir: missing operand");
        resp->resp = res;
        resp->resp_len = 50;

        return -1;
    }

    insertfiles(cli, conn, dir_name, 1, 0, NULL);
    resp->if_success = true;
    return 0;
}

int mvCmd(Response_t *resp, Command_t *cmd, Client_t *cli, MYSQL *conn)
{
    char sql_select[1024] = {0};
    char sql_update[1024] = {0};
    char dest_path[256] = {0};
    char file_path[512] = {0};
    MYSQL_RES *result = NULL;
    MYSQL_ROW row;

    // 获取用户id
    sprintf(sql_select, "select user_id from users where username = '%s'", cli->user_info.name);
    result = excutesql(sql_select, conn);
    row = mysql_fetch_row(result);
    int user_id = atoi(row[0]);
    mysql_free_result(result);

    //获取目标路径的parent_id
    if(cmd->arg2[0] == '/')
    {
        strcpy(dest_path, cmd->arg2);
    }
    else
    {
        strcpy(dest_path, cli->cur_path);
        strcat(dest_path, cmd->arg2);
    }
    sprintf(sql_select, "select file_id from files where user_id = %d and file_path = '%s'", user_id, dest_path);
    result = excutesql(sql_select, conn);
    row = mysql_fetch_row(result);
    if(row == NULL)
    {
        //路径不存在
        resp->resp = (char *)calloc(128, 1);
        strcpy(resp->resp, "dest path is not exit!\n");
        resp->resp_len = 128;
        resp->if_success = false; 
        return -1;
    }

    int parent_id = atoi(row[0]);
    mysql_free_result(result);

    //获取源路径的file_id
    sprintf(file_path, "%s%s", cli->cur_path, cmd->arg1);
    sprintf(sql_select, "select file_id, file_name from files where user_id = %d and file_path = '%s'", user_id, file_path);
    result = excutesql(sql_select, conn);
    row = mysql_fetch_row(result);
    if(row == NULL)
    {
        //路径不存在
        resp->resp = (char *)calloc(128, 1);
        strcpy(resp->resp, "src path is not exit!\n");
        resp->resp_len = 128;
        resp->if_success = false; 
        return -1;
    }

    int file_id = atoi(row[0]);
    mysql_free_result(result);

    //拼出新路径
    strcat(dest_path, row[1]);

    sprintf(sql_update, "update files set parent_id = %d, file_path = '%s' where file_id = %d", parent_id, dest_path, file_id);
    result = excutesql(sql_update, conn);
    mysql_free_result(result);
    resp->if_success = true;
    return 0;
}